import { tuple } from '@gnlab/utils'
import { App } from 'antd'
import services from '@/services'

/**
 * --------------------------------
 * 通用的 Props 定义
 * --------------------------------
 */

/**
 * 所有上传类型都要用到的 props
 */
export interface BaseProps<ValueT> {
  cdn?: boolean // 是否要上传到 CDN（默认为 false，仅应在明确需要外网访问路径时使用）
  tips?: React.ReactNode // 自定义提示语
  sizeLimit?: number // 上传文件大小限制（单位 M），为 0 时采用默认限制
  value?: ValueT | null
  onChange?: (value: ValueT | null) => void
}

/**
 * 各类型按需取用的 props
 */
export interface CommonProps {
  rectLimit?: RectLimit // 图片/视频尺寸限制，单位：像素
  duration?: number // 视频/音频的长度限制，单位：秒
  mimeType?: string // MIME Type 限制
}

export type RectLimit = { width: number; height: number } | null

const emptyFunc = () => {}
export function propsWithDefaults<T, Extra>(props: BaseProps<T> & CommonProps & Extra) {
  const {
    cdn = false,
    tips = '',
    sizeLimit = 0,
    onChange = emptyFunc,
    duration = 0,
    mimeType = '',
    value = null,
    ...rest
  } = props
  return { cdn, tips, sizeLimit, onChange, duration, mimeType, value, ...rest }
}

/**
 * --------------------------------
 * 实现上传行为
 * --------------------------------
 */
export type UploadedFile = { name: string; url: string }

export function useUpload(cdn = false) {
  const { message } = App.useApp()
  const [uploading, setUploading] = useState(false)

  const upload = useMemo(() => {
    function upload(files: File | Blob): Promise<UploadedFile | null>
    function upload(files: (File | Blob)[]): Promise<UploadedFile[]>
    async function upload(files: File | Blob | File[] | Blob[]) {
      const successFiles: UploadedFile[] = []
      const failedNames: string[] = []

      setUploading(true)
      const requests = (Array.isArray(files) ? files : [files]).map(async file => {
        const res = await services.utils.upload(file, cdn)
        if (res.success) successFiles.push({ name: file.name, url: res.data })
        else failedNames.push(file.name)
      })
      await Promise.all(requests)
      setUploading(false)

      if (failedNames.length) void message.warning('文件上传失败：' + failedNames.join('、'))

      return Array.isArray(files) ? successFiles : successFiles[0] ?? null
    }
    return upload
  }, [cdn, message])

  return tuple(uploading, upload)
}
